package shared.server;

import shared.mess.Content;
import shared.mess.ContentType;
import shared.mess.Message;
import shared.util.LRUCache;

import javax.swing.*;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author akaovi
 * @description 接收消息端
 * @createTime 2022/9/16 15:18
 */
public class Server {
    private InetAddress selfIp;

    private InetAddress clientIp;

    private boolean isLoop;

    private int port;

    private boolean refuseAllFiles;

    public LRUCache<String> getCache() {
        return cache;
    }

    private final LRUCache<String> cache = new LRUCache<>(10);

    public void setLoop(boolean loop) {
        isLoop = loop;
    }


    private ThreadPoolExecutor threadPool = null;

    public Server() {
        this.refuseAllFiles = false;
    }

    ;

    public Server(ThreadPoolExecutor threadPool) {
        this.refuseAllFiles = false;
        this.threadPool = threadPool;
        isLoop = false;
        try {
            selfIp = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }

    public Server(ThreadPoolExecutor threadPool, int port) {
        this(threadPool);
        this.port = port;
    }

    public Server(ThreadPoolExecutor threadPool, InetAddress clientIp) {
        this(threadPool);
        this.clientIp = clientIp;
    }


    public InetAddress getSelfIp() {
        return selfIp;
    }

    public void setSelfIp(InetAddress selfIp) {
        this.selfIp = selfIp;
    }

    public InetAddress getClientIp() {
        return clientIp;
    }

    public void setClientIp(InetAddress clientIp) {
        this.clientIp = clientIp;
    }

    public boolean isRefuseAllFiles() {
        return refuseAllFiles;
    }

    public void setRefuseAllFiles(boolean refuseAllFiles) {
        this.refuseAllFiles = refuseAllFiles;
    }

    public void doTask(Socket socket) {
        InputStream is = null;
        ObjectInputStream ois = null;
        try {
            is = socket.getInputStream();
            ois = new ObjectInputStream(is);
            Message ms = (Message) ois.readObject();
            Content ct = ms.content;
            if (ct.type == ContentType.TextType) {
                String ctStr = byteMessageToString(ct.details);
                if (ctStr != null && !"".equals(ctStr)) {
                    cacheTextMessage(ctStr);
                    showTextMessage(ctStr);
                }
            } else if (ct.type == ContentType.FileType && !this.refuseAllFiles) {
                // 处理拦截
                int res = JOptionPane.showConfirmDialog(
                        null,
                        "是否接收来自" + ms.from + "的文件",
                        "提示",
                        JOptionPane.YES_NO_CANCEL_OPTION);
                if (res == 0) {
                    // 接收
                    try {
                        saveFiles(ct);
                        JOptionPane.showMessageDialog(
                                null,
                                "接收来自" + ms.from + "的文件成功",
                                "提示",
                                JOptionPane.INFORMATION_MESSAGE);
                    } catch (Exception e) {
                        JOptionPane.showMessageDialog(
                                null,
                                "接收来自" + ms.from + "的文件失败",
                                "提示",
                                JOptionPane.INFORMATION_MESSAGE);
                    }
                } else {
                    JOptionPane.showMessageDialog(
                            null,
                            "拒绝接收来自" + ms.from + "的文件",
                            "提示",
                            JOptionPane.INFORMATION_MESSAGE);
                }
            }
//            System.out.println("收到了来自：" + ms.from + "的数据");
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private void cacheTextMessage(String s) {
        cache.put(s);
    }

    private String byteMessageToString(byte[] details) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(details, 0, details.length);
        String s = baos.toString(StandardCharsets.UTF_8);
        try {
            baos.close();
            return s;
        } catch (IOException e) {
            e.printStackTrace();
            return s;
        }
    }

    public void showTextMessage(String s) {
        // 文本输出
        System.out.println(s);
    }

    public void saveFiles(Content ct) throws IOException {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        try {
//            System.out.println("文件保存中");
            File file = new File("D:\\sharedFiles\\" + ct.name);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(ct.details, 0, ct.details.length);
//            System.out.println("文件保存完毕");
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void accept() {
        // 接收消息并展示
        ServerSocket ss = null;
        Socket socket = null;
        try {
            ss = new ServerSocket(this.port);
            isLoop = true;
            while (isLoop) {
                socket = ss.accept();
                Socket finalSocket = socket;
                threadPool.execute(() -> doTask(finalSocket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (ss != null) {
                try {
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        ThreadPoolExecutor threadPool = null;
        try {
            threadPool = new ThreadPoolExecutor(7, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>());
            Server server = new Server(threadPool);
            server.accept();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (threadPool != null) {
                threadPool.shutdown();
            }
        }
        if (threadPool != null) {
            threadPool.shutdown();
        }
    }
}
